Skip to content

Support readonly for all fields - #1677

Merged
Flo0807 merged 19 commits into
naymspace:developfrom
gmazzamuto:feature/readonly-fields
Sep 11, 2026
Merged

Flo0807 merged 19 commits into
naymspace:developfrom
gmazzamuto:feature/readonly-fields

Conversation

@gmazzamuto

Copy link
Copy Markdown
Contributor

Support :readonly option for all fields.

The :readonly field option, being shared among all fields, has been moved to the @config_schema of Backpex.Field. This should not be a breaking change.

Example of readonly fields:

Screenshot 2025-11-25 at 01-24-43 Edit User · Backpex

@Flo0807 Flo0807 added the enhancement Changes that are not breaking label Nov 28, 2025
Comment thread lib/backpex/html/core_components.ex Outdated
Comment thread lib/backpex/html/form.ex Outdated
Comment thread lib/backpex/html/form.ex Outdated
Comment thread lib/backpex/html/core_components.ex Outdated
Comment thread lib/backpex/fields/multi_select.ex
Comment thread lib/backpex/html/form.ex Outdated
Comment thread lib/backpex/html/resource.ex
The `:readonly` field option, being shared among all fields, has been
moved to the `@config_schema` of `Backpex.Field`.
@gmazzamuto
gmazzamuto force-pushed the feature/readonly-fields branch from 30ef1e3 to c2ab647 Compare December 23, 2025 17:27
Flo0807 added 11 commits April 22, 2026 15:40
Previously the readonly dropdown kept role="button", tabindex=0, and
aria-haspopup="true" while stripping the menu, producing a focusable
element that announces a popup that isn't there. Also removed the
fragile class-token-surgery that reached into caller class lists to
delete "input" and "bg-transparent" strings; callers now build their
own readonly-aware class lists using Phoenix's list syntax.
The drop target's phx-drop-target attribute was not gated on readonly,
so drag-and-drop still started uploads. Cancel buttons for in-progress
and existing entries remained clickable, letting users mutate file
state. The "Upload a file" <a> rendered as a dead link in readonly
mode — now a plain <span> with the interactive classes removed.
text-base-content/40 on bg-base-200 falls below 4.5:1 on stock
daisyUI themes. Bumped to /60 to match the codebase's standard
muted-text token (used in help_text / labels).
HTML's readonly and disabled have different a11y semantics: disabled
removes the element from the tab order and is frequently skipped by
screen readers in form-review mode, making the readonly value
invisible. For inputs that natively support readonly (text, number,
date, date_time, time, textarea, email, url, currency), keeping only
readonly={@readonly} is correct. Controls without native readonly
(select, multi_select, boolean, relations, upload) continue to use
disabled as before.
Previously the readonly branch removed the delete checkbox but left
an orphaned <label for> pointing at nothing, wrapping a <div
class="btn btn-disabled"> with sr-only "Delete" text. Screen readers
announced a non-interactive "Delete" with a dangling label
association. Same problem for "Add entry" — rendered as a disabled
checkbox-masquerading-as-button. In readonly mode a user has no use
for either control, so they are now omitted entirely.
select_relational_field/1 and pivot_field/1 previously did not
receive the parent field's readonly flag. The main UI already hid
the triggers that invoke them, so no live regression — but any
future path that opens the relation modal (e.g. programmatic
push_event, pre-populated newest_relational) would render an
editable select on a readonly field. Now both components declare
readonly as an explicit attr and forward it to their inputs.
The guide listed only Date, DateTime, Number, Text, Textarea as
readonly-capable. With this PR, readonly is a global Backpex.Field
option and most field types support it. Documented the three
rendering strategies (native-readonly, disabled, custom) and the
per-field quirks for Upload, InlineCRUD, HasManyThrough, Boolean.
…ledocs

These three fields render readonly with custom UI changes that hide
or disable elements beyond the standard readonly/disabled attribute.
Added short Readonly sections to the moduledocs so users discover
this behavior without reading the guide.
Covers the readonly-branch HTML surface of both components:
dropdown has no role/tabindex/aria-haspopup/menu when readonly;
multi_select prompt uses /60 contrast and badges render without
primary color or remove controls. Sets up test/html/ as the home
for future HTML component tests (the repo previously had no
component-level coverage).
This fixes a bug caused by Ecto's `:sort_param` and `:drop_param` when
the field is readonly. The hidden fields need to be marked as disabled
to prevent being sent when the InlineCRUD field is readonly. Otherwise
the following bug happens. Steps to reproduce:

* in UserLive, set the social_links field as readonly
* in the edit view, make any change to the form
* the social_links will disappear because Ecto's `cast_embed` doesn't
  work properly
@gmazzamuto

Copy link
Copy Markdown
Contributor Author

Hi there, I have merged the latest develop branch and added an extra commit to fix a bug.

What is left to do is to homogenize the look and feel of disabled fields. At the moment, disabled text fields look differently than other fields such as Select. I see that you are favoring the readonly attribute in place of disabled for accessibility issues and also because they have different meanings. This makes sense, but DaisyUI prefers disabled instead. See here. Maybe we'll have to find another way to visually render a field as readonly/disabled.

@Flo0807
Flo0807 added this pull request to the merge queue Sep 11, 2026
Merged via the queue into naymspace:develop with commit 1114c4c Sep 11, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Changes that are not breaking

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants